using System;
using System.Collections.Specialized;
using System.Web.Security;
using Castle.MonoRail.Framework;
using WineCellar.Web.Common;

namespace WineCellar.Web.Controllers
{
    [Layout("index")]
    public class MembershipController:MessageControllerBase<MembershipController.PropertyAccessorImpl>
    {
        public class MembershipUserStore
        {
            private string _userName;
            private string _password;
            private string _passwordVerify;
            private string _email;
            private string _passwordQuestion;
            private string _passwordAnswer;
            private object _providerUserKey;
            private string [] _assignedRoles;

            public MembershipUserStore()
            {
            }
            
            public string UserName
            {
                get { return this._userName; }
                set { this._userName = value; }
            }
            public string Password
            {
                get { return this._password; }
                set { this._password = value; }
            }
            public string PasswordVerify
            {
                get { return this._passwordVerify; }
                set { this._passwordVerify = value; }
            }
            public string Email
            {
                get { return this._email; }
                set { this._email = value; }
            }
            public string PasswordQuestion
            {
                get { return this._passwordQuestion; }
                set { this._passwordQuestion = value; }
            }
            public string PasswordAnswer
            {
                get { return this._passwordAnswer; }
                set { this._passwordAnswer = value; }
            }
            public object ProviderUserKey
            {
                get { return this._providerUserKey; }
                set { this._providerUserKey = value; }
            }
            public string[] AssignedRoles
            {
                get { return this._assignedRoles; }
                set { this._assignedRoles = value; }
            }
            public MembershipCreateStatus CreateUser(bool isApproved, MembershipProvider membershipProvider)
            {
                MembershipCreateStatus membershipCreateStatus;

                membershipProvider.CreateUser(this._userName, this._password, this._email, this._passwordQuestion, this._passwordAnswer,
                    isApproved, Guid.NewGuid(), out membershipCreateStatus);
                return membershipCreateStatus;
            }
            
        }
        
        public class PropertyAccessorImpl:PropertyAccessorBase
        {
            private class Constants
            {
		        public const string Users= "users";
			    public const string CurrentUser= "currentUser";
                public const string NewPassword= "newPassword";
                public const string Roles = "roles";
                public const string CurrentUserRoles="currentUserRoles";
            }
            public PropertyAccessorImpl()
            {
            }
            
            public MembershipUser CurrentUser
            {
                get { return (MembershipUser)this.Flash[Constants.CurrentUser]; }
                set { this.Flash[Constants.CurrentUser] = value; }
            }
            public MembershipUserCollection Users
            {
                get { return (MembershipUserCollection)this.Flash[Constants.Users]; }
                set { this.Flash[Constants.Users] = value; }
            }
            public string NewPassword
            {
                get { return (string)this.Flash[Constants.NewPassword]; }
                set { this.Flash[Constants.NewPassword] = value; }
            }
            public string[] Roles
            {
                get { return (string[])this.Flash[Constants.Roles]; }
                set { this.Flash[Constants.Roles] = value; }
            }
            public string[] CurrentUserRoles
            {
                get { return (string[])this.Flash[Constants.CurrentUserRoles]; }
                set { this.Flash[Constants.CurrentUserRoles] = value; }
            }
        }
        
        
        public void List()
        {
            
            int totalRecords;
            this.PropertyAccessor.Users = GetMembershipProvider().GetAllUsers(0,1,out totalRecords);
            //retrieve again using the full record count
            this.PropertyAccessor.Users = GetMembershipProvider().GetAllUsers(0, totalRecords, out totalRecords);
        }
        public void ShowAdd()
        {
            this.PropertyAccessor.CurrentUserRoles = new string[] { };
            this.PropertyAccessor.Roles = Roles.GetAllRoles();
        }

        public void ShowEdit(Guid providerUserKey)
        {
            this.PropertyAccessor.Roles = Roles.GetAllRoles();
            if (this.PropertyAccessor.CurrentUser == null)
            {
                this.PropertyAccessor.CurrentUser = GetMembershipProvider().GetUser(providerUserKey,false);
                this.PropertyAccessor.CurrentUserRoles = Roles.GetRolesForUser(this.PropertyAccessor.CurrentUser.UserName);
            }
        }
        
        public void ChangeEmail(Guid providerUserKey, string email)
        {
            this.PropertyAccessor.CurrentUser = GetMembershipProvider().GetUser(providerUserKey, false);
            this.PropertyAccessor.CurrentUser.Email = email;
            GetMembershipProvider().UpdateUser(this.PropertyAccessor.CurrentUser);
        }
        public void ChangePassword(Guid providerUserKey, string newPassword, string newPasswordVerify)
        {
            if (newPassword != newPasswordVerify)
            {
                this.PropertyAccessor.AddMessage(new Message("Password does not match with verification password.", Message.Enums.MessageClass.Warning));
                RedirectToAction("ShowEdit");
            }
            else
            {
                this.PropertyAccessor.CurrentUser = GetMembershipProvider().GetUser(providerUserKey, false);
                //reset password
                string tempPassword = this.PropertyAccessor.CurrentUser.ResetPassword();
                this.PropertyAccessor.CurrentUser.ChangePassword(tempPassword, newPassword);
                this.PropertyAccessor.AddMessage(new Message("Password changed successfully.", Message.Enums.MessageClass.Information));
                RedirectToAction("List");
            }
        }
        public void ChangeRoles(Guid providerUserKey, string[] currentUserRoles)
        {
            this.PropertyAccessor.CurrentUser = GetMembershipProvider().GetUser(providerUserKey, false);
            //create a dictionary for incoming role list
            StringDictionary assignedUserRoles = CreateStringDictionary(currentUserRoles);
            foreach (string role in Roles.GetAllRoles())
            {
                if (assignedUserRoles.ContainsKey(role) != Roles.IsUserInRole(this.PropertyAccessor.CurrentUser.UserName,role))
                {
                    if (assignedUserRoles.ContainsKey(role))
                        Roles.AddUserToRole(this.PropertyAccessor.CurrentUser.UserName, role);
                    else
                        Roles.RemoveUserFromRole(this.PropertyAccessor.CurrentUser.UserName, role);
                }
            }
            this.PropertyAccessor.Messages.Add(new Message(string.Format("Role for user {0} changed successfully.", this.PropertyAccessor.CurrentUser.UserName), Message.Enums.MessageClass.Information));

            RedirectToAction("List");
        }
        private StringDictionary CreateStringDictionary(string[] values)
        {
            StringDictionary resultDictionary = new StringDictionary();
            foreach (string value in values)
            {
                resultDictionary.Add(value, value);
            }
            return resultDictionary;
        }
        public void ResetPassword(Guid providerUserKey)
        {
            this.PropertyAccessor.CurrentUser= GetMembershipProvider().GetUser(providerUserKey, false);
            this.PropertyAccessor.NewPassword = this.PropertyAccessor.CurrentUser.ResetPassword();
            
            
        }
        public void UnlockUser(Guid providerUserKey)
        {
            MembershipUser user = GetMembershipProvider().GetUser(providerUserKey, false);
            user.UnlockUser();
            this.PropertyAccessor.AddMessage(new Message(string.Format("User {0} unlocked successfully.", user.UserName), Message.Enums.MessageClass.Information));
            RedirectToAction("List");
        }
        public void ShowDelete(Guid providerUserKey)
        {
            this.PropertyAccessor.CurrentUser = GetMembershipProvider().GetUser(providerUserKey,false);
            
        }
        public void Delete(Guid providerUserKey, string action)
        {
            if (action.ToLower() == "confirm")
            {
                MembershipUser user = GetMembershipProvider().GetUser(providerUserKey, false);
                GetMembershipProvider().DeleteUser(user.UserName, true);
                this.PropertyAccessor.AddMessage(new Message(string.Format("User {0} deleted successfully.", user.UserName), Message.Enums.MessageClass.Information));
            }
            RedirectToAction("List");
        }

        public void Add([DataBind("user",From=ParamStore.Form)] MembershipUserStore user) 
        {
            MembershipCreateStatus membershipCreateStatus=user.CreateUser(true, GetMembershipProvider());
            if (membershipCreateStatus == MembershipCreateStatus.Success)
            {
                this.PropertyAccessor.AddMessage(new Message("User created successfully.", Message.Enums.MessageClass.Information));
                Roles.AddUserToRoles(user.UserName, user.AssignedRoles);   
                RedirectToAction("List");
            }
            else
            {
                this.PropertyAccessor.AddMessage(new Message(string.Format("Unable to add user. Reason:{0}",membershipCreateStatus),Message.Enums.MessageClass.Warning));
                RedirectToAction("ShowAdd");
            }
            
            
        }

        protected MembershipProvider GetMembershipProvider()
        {
            MembershipManagerSection membershipManagerSection = MembershipManagerSection.GetConfig();
            return Membership.Providers[membershipManagerSection.AdministrationProviderName];
        }

    }
}
